﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using DotSpatial.Controls;
using DotSpatial.Extensions;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using DotSpatial.Plugins.ExtensionManager;
using NuGet;

namespace DotSpatial.SampleProjects.SampleProjectManager
{
    public partial class TemplateForm : Form
    {
        #region Constants and Fields

        
        private const string SampleProject = "SampleProject";
        private readonly Packages packages = new Packages();
        private const string msgNotFound = "No project templates were found. Please install the templates.";

        #endregion
        
        /// <summary>
        /// Gets the list tools available.
        /// </summary>
        private IEnumerable<SampleProjectInfo> FindSampleProjectFiles()
        {
            List<SampleProjectInfo> sampleProjectList = new List<SampleProjectInfo>();
            foreach (string absolutePath in Directory.EnumerateFiles(AppManager.AbsolutePathToExtensions, "*.dspx", SearchOption.AllDirectories))
            {
                var sample = new SampleProjectInfo();
                sample.AbsolutePathToProjectFile = absolutePath;
                sample.Name = Path.GetFileNameWithoutExtension(absolutePath);
                sample.Description = "description";
                sample.Version = "1.0";
                sampleProjectList.Add(sample);
            }
            return sampleProjectList;
        }

        public IEnumerable<SampleProjectInfo> SampleProjects { get; set; }
        
        public TemplateForm(AppManager app)
        {
            InitializeComponent();
            App = app;

            Bitmap b = new Bitmap(Properties.Resources.map32x32);
            this.Icon = Icon.FromHandle(b.GetHicon());

            UpdatePackageList();
            SampleProjects = new List<SampleProjectInfo>();
            listBoxTemplates.SelectedIndexChanged += new EventHandler(listBoxTemplates_SelectedIndexChanged);
            uxOnlineProjects.SelectedIndexChanged += new EventHandler(uxOnlineProjects_SelectedIndexChanged);
        }

        

        public AppManager App { get; set; }

        private void TemplateForm_Load(object sender, EventArgs e)
        {
            UpdateInstalledProjectsList();
        }

        private void UpdateInstalledProjectsList()
        {
            SampleProjects = FindSampleProjectFiles();

            if (!SampleProjects.Any())
            {
                listBoxTemplates.DataSource = null;
                listBoxTemplates.Items.Add(msgNotFound);
                return;
            }

            listBoxTemplates.DataSource = SampleProjects;
            listBoxTemplates.DisplayMember = "Name";
            uxOnlineProjects.SelectedIndex = 0;
            btnInstall.Enabled = true;
        }

        private void UpdatePackageList()
        {
            uxOnlineProjects.Items.Add("Loading...");
            var task = Task.Factory.StartNew(() =>
            {
                var result = packages.Repo.GetPackages().Where(p => p.IsLatestVersion && (p.Tags.Contains(SampleProject))).ToArray();
                return result;
            });

            task.ContinueWith((t) =>
            {
                uxOnlineProjects.Items.Clear();
                if (t.Exception == null)
                    uxOnlineProjects.Items.AddRange(t.Result);
                else
                    uxOnlineProjects.Items.Add(t.Exception.Message);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            SampleProjectInfo selectedProject = listBoxTemplates.SelectedItem as SampleProjectInfo;
            OpenSampleProject(selectedProject);
        }

        void listBoxTemplates_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBoxTemplates.SelectedIndex >= 0 && listBoxTemplates.SelectedItem.ToString() != msgNotFound)
            {
                btnUninstall.Enabled = true;
            }
            else
            {
                btnUninstall.Enabled = false;
            }
        }

        void uxOnlineProjects_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (uxOnlineProjects.Items.Count == 0)
            {
                btnInstall.Enabled = false;
                return;
            }
            
            IPackage pack = uxOnlineProjects.SelectedItem as IPackage;
            if (pack == null) 
            {
                btnInstall.Enabled = false;
                return;
            }

            if (IsPackageInstalled(pack))
            {
                btnInstall.Enabled = false;
            }
            else
            {
                btnInstall.Enabled = true;
            }
        }

        private void OpenSampleProject(SampleProjectInfo sample)
        {
            string projectFile = sample.AbsolutePathToProjectFile;
            try
            {
                //string newProjectFile = CopyToDocumentsFolder(projectFile);
                App.SerializationManager.OpenProject(projectFile);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + @" File: " + projectFile);
            }
        }

        private void UninstallSampleProject(SampleProjectInfo sample)
        {
            if (App.SerializationManager.CurrentProjectFile == sample.AbsolutePathToProjectFile)
            {
                MessageBox.Show("Cannot uninstall " + sample.Name + ". The project is currently open. Please close current project and try again.");
                return;
            }
            else
            {
                string dir = Path.GetDirectoryName(sample.AbsolutePathToProjectFile);
                DirectoryInfo packageDir = Directory.GetParent(dir);
                try
                {
                    foreach (string file in Directory.EnumerateFiles(dir))
                    {
                        File.Delete(file);
                    }
                    Directory.Delete(dir);
                    foreach (FileInfo file in packageDir.GetFiles())
                    {
                        file.Delete();
                    }
                    if (!packageDir.GetDirectories().Any() && !packageDir.GetFiles().Any())
                    {
                        packageDir.Delete();
                    }
                }
                catch (IOException ex)
                {
                    MessageBox.Show("Some files could not be uninstalled. " + ex.Message);
                }
            }
            MessageBox.Show("The project was successfully uninstalled.");
        }
        

        public string SelectedTemplate { get; set; }

        private string CopyToDocumentsFolder(string projectFile)
        {
            string projDir = Path.GetDirectoryName(projectFile);
            string docsDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

            string dotSpatialDir = Path.Combine(docsDir, "DotSpatial");
            if (!Directory.Exists(dotSpatialDir))
            {
                //todo check if the directory can be created
                Directory.CreateDirectory(dotSpatialDir);
            }

            string projName = Path.GetFileNameWithoutExtension(projectFile);
            string newProjDir = Path.Combine(dotSpatialDir, projName);
            if (!Directory.Exists(newProjDir))
            {
                Directory.CreateDirectory(newProjDir);
            }

            foreach (string file in Directory.GetFiles(projDir))
            {
                File.Copy(file, Path.Combine(newProjDir, Path.GetFileName(file)),true);
            }
            string newProjFile = Path.Combine(newProjDir, Path.GetFileName(projectFile));
            return newProjFile;
        }

        private static string GetPackagePath(IPackage pack)
        {
            string path = Path.Combine(AppManager.AbsolutePathToExtensions, AppManager.PackageDirectory, GetPackageFolderName(pack));
            return path;
        }

        private static string GetPackageFolderName(IPackage pack)
        {
            return String.Format("{0}.{1}", pack.Id, pack.Version);
        }

        private static bool IsPackageInstalled(IPackage pack)
        {
            string folder = GetPackagePath(pack);
            if (!Directory.Exists(folder)) return false;

            if (Directory.EnumerateFiles(folder, "*.dspx", SearchOption.AllDirectories).Any())
            {
                return true;
            }
            return false;
        }

        private void btnOKOnline_Click(object sender, EventArgs e)
        {
            if (uxOnlineProjects.SelectedItem != null)
            {
                btnInstall.Enabled = false;
                var pack = uxOnlineProjects.SelectedItem as IPackage;

                App.ProgressHandler.Progress(null, 0, "Downloading " + pack.Title);

                var task = Task.Factory.StartNew(() =>
                {
                    // Download the extension.
                    packages.Install(pack.Id);
                });

                // UI related work.
                task.ContinueWith((t) =>
                {
                    App.ProgressHandler.Progress(null, 0, "Installing " + pack.Title);

                    UpdateInstalledProjectsList();
                    App.ProgressHandler.Progress(null, 0, "Ready.");
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }
        }

        private void ListBoxTemplates_DoubleClick(object sender, EventArgs e)
        {
            SampleProjectInfo selectedProject = listBoxTemplates.SelectedItem as SampleProjectInfo;
            OpenSampleProject(selectedProject);
            Close();
        }

        private void btnUninstall_Click(object sender, EventArgs e)
        {
            SampleProjectInfo selectedProject = listBoxTemplates.SelectedItem as SampleProjectInfo;
            UninstallSampleProject(selectedProject);
            UpdateInstalledProjectsList();
        }
    }
}
